package com.ylr.admin.framework.service.impl;

import com.ylr.admin.common.dto.role.RoleDto;
import com.ylr.admin.common.dto.role.RoleEnumDto;
import com.ylr.admin.common.dto.role.SimpleRoleDto;
import com.ylr.admin.common.enums.RoleEnum;
import com.ylr.admin.common.vo.role.RoleFormVo;
import com.ylr.admin.common.vo.role.RoleVo;
import com.ylr.admin.framework.entity.RoleEntity;
import com.ylr.admin.framework.mapper.RoleMapper;
import com.ylr.admin.framework.service.RoleService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ylr.base.common.dto.GroupDto;
import com.ylr.base.common.dto.NameValue;
import com.ylr.base.common.dto.PageDto;
import com.ylr.base.common.enums.CommonEnum;
import com.ylr.base.common.enums.ResultEnum;
import com.ylr.base.common.exception.YlrException;
import com.ylr.base.common.po.user.UserPo;
import com.ylr.base.common.tool.PageQuery;
import com.ylr.base.common.utils.ThrottleUtils;
import com.ylr.base.common.utils.UserUtils;
import com.ylr.base.common.vo.UpdateStatusVo;
import com.ylr.base.framework.service.AsyncService;
import com.ylr.base.framework.service.SnowflakeService;
import com.ylr.config.common.enums.KeyEnum;
import com.ylr.config.framework.resolver.YcMappingResolver;
import com.ylr.redis.framework.service.RedisService;
import com.ylr.redis.framework.service.RedisStringService;
import com.ylr.redis.framework.service.RedissonService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2023-04-21 11:45:26
 * className: RoleServiceImpl
 * version: 1.0
 * description:
 */
@Service("roleService")
@AllArgsConstructor
public class RoleServiceImpl extends ServiceImpl<RoleMapper, RoleEntity> implements RoleService {

    private static final Logger log = LoggerFactory.getLogger(RoleServiceImpl.class);

    private final YcMappingResolver ycMappingResolver;

    private final SnowflakeService snowflakeService;

    private final AsyncService asyncService;

    private final RedisStringService redisStringService;

    private final RedisService redisService;

    private final RedissonService redissonService;

    private final ThrottleUtils throttleUtils;

    @Override
    public void saveRole(RoleVo roleVo) {

        // 获取正在保存角色的用户对象
        UserPo userPo = UserUtils.getUser();
        Date date = new Date();

        RoleEntity role = this.getRole(roleVo, userPo, date);
        // 插入数据
        baseMapper.insert(role);
        log.info("角色插入完成");

    }

    @Override
    public PageDto<RoleDto> pageRoleList(RoleFormVo roleFormVo) {
        // mp分页对象
        Page<RoleEntity> page = PageQuery.initPage(roleFormVo);

        LambdaQueryWrapper<RoleEntity> pageLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 匹配条件
        pageLambdaQueryWrapper.eq(Objects.nonNull(roleFormVo.getType()), RoleEntity::getType, roleFormVo.getType())
                .eq(Objects.nonNull(roleFormVo.getStatus()), RoleEntity::getStatus, roleFormVo.getStatus())
                .and(StringUtils.isNotBlank(roleFormVo.getWord()), _pageLambdaQueryWrapper -> {
                    _pageLambdaQueryWrapper.like(RoleEntity::getRoleName, roleFormVo.getWord())
                            .or()
                            .like(RoleEntity::getRoleKey, roleFormVo.getWord());
                })
                .eq(RoleEntity::getDeleteStatus, CommonEnum.DELETE_NO.getValue());
        // 分页查询
        baseMapper.selectPage(page, pageLambdaQueryWrapper);

        List<RoleEntity> roleList = page.getRecords();
        long totalNum = page.getTotal();
        // 数据封装
        List<RoleDto> roleDtoList = new ArrayList<>(roleList.size());
        for (RoleEntity role : roleList) {
            roleDtoList.add(this.getRoleDto(role));
        }

        return new PageDto<>(roleDtoList, totalNum, roleFormVo.getPageNo(), roleFormVo.getPageSize());
    }

    @Override
    public List<GroupDto<SimpleRoleDto>> getList() {

        LambdaQueryWrapper<RoleEntity> roleLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 查询字段
        roleLambdaQueryWrapper.select(RoleEntity::getId, RoleEntity::getRoleName, RoleEntity::getRoleKey, RoleEntity::getType, RoleEntity::getSort, RoleEntity::getStatus);
        // 匹配条件
        roleLambdaQueryWrapper.eq(RoleEntity::getStatus, CommonEnum.STATUS_USE.getValue())
                .eq(RoleEntity::getDeleteStatus, CommonEnum.DELETE_NO.getValue());
        // 查询数据
        List<RoleEntity> roleList = baseMapper.selectList(roleLambdaQueryWrapper);
        if (roleList.isEmpty()) {
            log.info("角色列表为空");
            return Collections.emptyList();
        }

        // 数据构造
        Map<Integer, List<SimpleRoleDto>> roleMap = roleList.stream()
                .map(this::getSimpleRoleDto)
                .sorted(Comparator.comparing(SimpleRoleDto::getSort))
                .collect(Collectors.groupingBy(SimpleRoleDto::getType));
        // 获取角色类型枚举列表
        List<NameValue<Integer>> typeEnumList = RoleEnum.getTypeEnumList();

        return typeEnumList.stream()
                .map(nameValue -> {
                    List<SimpleRoleDto> _roleList = roleMap.get(nameValue.getValue());
                    if (Objects.isNull(_roleList)) {
                        return null;
                    }
                    GroupDto<SimpleRoleDto> groupDto = new GroupDto<>();
                    groupDto.setKey(nameValue.getValue().toString())
                            .setName(nameValue.getName())
                            .setList(_roleList);
                    return groupDto;
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    @Override
    public RoleDto getRole(Long id) {
        // 查询数据
        RoleEntity role = baseMapper.selectById(id);
        if (Objects.isNull(role)) {
            log.warn("角色不存在");
            throw new YlrException(ResultEnum.NOT_FOUND);
        }
        if (CommonEnum.DELETE_YES.getValue().equals(role.getDeleteStatus())) {
            log.warn("角色已被删除");
            throw new YlrException(ResultEnum.NOT_FOUND);
        }
        return this.getRoleDto(role);
    }

    @Override
    public Integer getNextSort() {
        // 查询数据
        Integer maxSort = baseMapper.selectMaxSort(CommonEnum.DELETE_NO.getValue());
        if (Objects.isNull(maxSort)) {
            maxSort = 0;
        }
        return maxSort + 1;
    }

    @Override
    public RoleEnumDto getPageEnums() {

        RoleEnumDto roleEnumDto = new RoleEnumDto();
        roleEnumDto.setStatusEnumList(CommonEnum.getStatusEnumList());

        return roleEnumDto;
    }

    @Override
    public Set<String> getRoleKeySet(Set<Long> roleIdSet) {
        return baseMapper.selectRoleKeySet(roleIdSet, CommonEnum.DELETE_NO.getValue());
    }

    @Override
    public void updateRole(RoleVo roleVo) {
        // 获取正在修改角色的用户对象
        UserPo userPo = UserUtils.getUser();
        Date date = new Date();

        RoleEntity role = new RoleEntity();
        role.setId(role.getId())
            .setRoleName(roleVo.getRoleName())
            .setRoleKey(roleVo.getRoleKey())
            .setSort(roleVo.getSort())
            .setUpdateTime(date)
            .setUpdateUser(userPo.getUsername())
            .setUpdateUserId(userPo.getId());
        // 更新数据
        int count = baseMapper.updateById(role);
        log.info("角色更新完成。count={}", count);
        if (count == 0) {
            throw new YlrException(ResultEnum.NOT_FOUND);
        }
    }

    @Override
    public void updateRoleStatus(UpdateStatusVo updateStatusVo) {
        // 获取正在修改角色状态的用户对象
        UserPo userPo = UserUtils.getUser();
        Date date = new Date();

        LambdaUpdateWrapper<RoleEntity> roleLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        // 设置字段值
        roleLambdaUpdateWrapper.set(RoleEntity::getStatus, updateStatusVo.getStatus())
                .set(RoleEntity::getUpdateTime, date)
                .set(RoleEntity::getUpdateUser, userPo.getUsername())
                .set(RoleEntity::getUpdateUserId, userPo.getId());
        // 匹配条件
        roleLambdaUpdateWrapper.in(RoleEntity::getId, updateStatusVo.getIdList())
                .eq(RoleEntity::getDeleteStatus, CommonEnum.DELETE_NO.getValue());
        // 更新数据
        int count = baseMapper.update(null, roleLambdaUpdateWrapper);
        log.info("修改角色状态完成。count={}", count);
        if (count == 0) {
            throw new YlrException(ResultEnum.NOT_FOUND);
        }
    }

    @Override
    public void deleteRole(List<Long> idList) {

        // 校验删除数量是否超过最大阈值
        Integer batchMax = ycMappingResolver.getValue(KeyEnum.BATCH_OPT_NUM.getKey(), Integer.class);
        if (batchMax < idList.size()) {
            log.warn("一次删除接口数量超过阈值。batchMax={} idListSize={}", batchMax, idList.size());
            throw new YlrException(ResultEnum.BATCH_FAIL);
        }

        // 获取正在删除角色的用户对象
        UserPo userPo = UserUtils.getUser();
        Date date = new Date();

        LambdaUpdateWrapper<RoleEntity> roleLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        // 设置字段值
        roleLambdaUpdateWrapper.set(RoleEntity::getDeleteStatus, CommonEnum.DELETE_YES.getValue())
                .set(RoleEntity::getUpdateTime, date)
                .set(RoleEntity::getUpdateUser, userPo.getUsername())
                .set(RoleEntity::getUpdateUserId, userPo.getId());
        // 匹配条件
        roleLambdaUpdateWrapper.in(RoleEntity::getId, idList)
                .eq(RoleEntity::getDeleteStatus, CommonEnum.DELETE_NO.getValue());
        // 更新数据
        int count = baseMapper.update(null, roleLambdaUpdateWrapper);
        log.info("删除角色完成。count={}", count);
        if (count == 0) {
            throw new YlrException(ResultEnum.NOT_FOUND);
        }
    }

    /**
     * 角色参数转化成角色实体对象
     * @param roleVo 参数对象
     * @return 角色实体对象
     */
    private RoleEntity getRole(RoleVo roleVo, UserPo userPo, Date date) {
        RoleEntity role = new RoleEntity();
        role.setId(snowflakeService.getId())
                .setRoleName(roleVo.getRoleName())
                .setRoleKey(roleVo.getRoleKey())
                .setType(roleVo.getType())
                .setSort(roleVo.getSort())
                .setStatus(CommonEnum.STATUS_USE.getValue())
                .setDeleteStatus(CommonEnum.DELETE_NO.getValue())
                .setUpdateTime(date)
                .setUpdateUser(userPo.getUsername())
                .setUpdateUserId(userPo.getId())
                .setCreateTime(date)
                .setCreateUser(userPo.getUsername())
                .setCreateUserId(userPo.getId())
                .setRemark(Optional.ofNullable(roleVo.getRemark()).orElse(StringUtils.EMPTY));
        return role;
    }

    /**
     * 角色实体对象封装
     * @param role 角色对象
     * @return 封装结果
     */
    private RoleDto getRoleDto(RoleEntity role) {
        RoleDto roleDto = new RoleDto();
        roleDto.setId(role.getId().toString())
                .setRoleName(role.getRoleName())
                .setRoleKey(role.getRoleKey())
                .setType(role.getType())
                .setSort(role.getSort())
                .setStatus(role.getStatus())
                .setUpdateTime(role.getUpdateTime())
                .setUpdateUser(role.getUpdateUser())
                .setCreateTime(role.getCreateTime())
                .setCreateUser(role.getCreateUser());
        return roleDto;
    }

    /**
     * 角色实体对象封装
     * @param role 角色对象
     * @return 封装结果
     */
    private SimpleRoleDto getSimpleRoleDto(RoleEntity role) {
        SimpleRoleDto roleDto = new SimpleRoleDto();
        roleDto.setId(role.getId().toString())
                .setRoleName(role.getRoleName())
                .setRoleKey(role.getRoleKey())
                .setType(role.getType())
                .setSort(role.getSort())
                .setStatus(role.getStatus());
        return roleDto;
    }

}